package com.zdp.chat.controller;

import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
import com.anwen.mongo.execute.SqlExecute;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zdp.chat.common.CommonConstant;
import com.zdp.chat.entity.mongo.*;
import com.zdp.chat.enums.*;
import com.zdp.chat.service.mongo.*;
import com.zdp.chat.util.CacheUtils;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;

@RequiredArgsConstructor
@RestController
@RequestMapping("/friend")
public class FriendController {

    private final FriendApplyDocService friendApplyDocService;

    private final FriendDocService friendDocService;

    private final RoomDocService roomDocService;

    private final RoomUserDocService roomUserDocService;

    private final RoomMessageDocService roomMessageDocService;

    private final RedissonClient redissonClient;

    private final RedisTemplate redisTemplate;

    @PostMapping("/apply")
    public Object apply(@RequestBody JSONObject param) {
        String applyUid = param.getString("applyUid");
        String friendUid = param.getString("friendUid");


        LambdaQueryChainWrapper<FriendDoc> queryChainWrapper = new LambdaQueryChainWrapper<FriendDoc>(new SqlExecute(), FriendDoc.class)
                .eq(FriendDoc::getUid, applyUid).eq(FriendDoc::getFriendUid, friendUid);

        long count = friendDocService.count(queryChainWrapper);
        if (count > 0) {
            return "已是好友请勿重复添加";
        }

        LocalDateTime now = LocalDateTime.now();

        FriendApplyDoc friendApplyDoc = new FriendApplyDoc();
        friendApplyDoc.setApplyUid(applyUid);
        friendApplyDoc.setFriendUid(friendUid);
        friendApplyDoc.setApplyTime(now);
        friendApplyDoc.setStatus(2);
        friendApplyDocService.save(friendApplyDoc);

        List<FriendDoc> friendDocList = Lists.newArrayList();
        FriendDoc friendDoc = new FriendDoc();
        friendDoc.setUid(applyUid);
        friendDoc.setFriendUid(friendUid);
        friendDoc.setCreateTime(now);
        FriendDoc friendDoc1 = new FriendDoc();
        friendDoc1.setUid(friendUid);
        friendDoc1.setFriendUid(applyUid);
        friendDoc1.setCreateTime(LocalDateTime.now());
        friendDocList.add(friendDoc);
        friendDocList.add(friendDoc1);
        friendDocService.saveBatch(friendDocList);

        RoomDoc roomDoc = new RoomDoc();
        SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator(1, 0);
        Long roomId = snowflakeGenerator.next();
        roomDoc.setId(roomId);
        roomDoc.setRoomType(RoomTypeEnum.FRIEND.getType());
        roomDoc.setRoomName("room name is " + applyUid + ":" + friendUid);
        Map<String, String> picMap = Maps.newHashMap();
        picMap.put(applyUid, "http://" + applyUid + "/" + RandomUtil.randomNumbers(10) + ".jpg");
        picMap.put(friendUid, "http://" + friendUid + "/" + RandomUtil.randomNumbers(10) + ".jpg");
        roomDoc.setRoomPic(JSONObject.toJSONString(picMap));
        roomDoc.setCreateTime(now);
        roomDocService.save(roomDoc);

        List<RoomUserDoc> roomUserDocList = Lists.newArrayList();
        RoomUserDoc roomUserDoc = new RoomUserDoc();
        roomUserDoc.setRoomType(RoomTypeEnum.FRIEND.getType());
        roomUserDoc.setRoomId(roomId);
        roomUserDoc.setUid(applyUid);
        roomUserDoc.setJoinTime(now);
        roomUserDoc.setRole(GroupRoleEnum.MEMBER.getType());
        RoomUserDoc roomUserDoc1 = new RoomUserDoc();
        roomUserDoc1.setRoomType(RoomTypeEnum.FRIEND.getType());
        roomUserDoc1.setRoomId(roomId);
        roomUserDoc1.setUid(friendUid);
        roomUserDoc1.setJoinTime(now);
        roomUserDoc1.setRole(GroupRoleEnum.MEMBER.getType());
        roomUserDocList.add(roomUserDoc);
        roomUserDocList.add(roomUserDoc1);
        roomUserDocService.saveBatch(roomUserDocList);

        RoomMessageDoc roomMessageDoc = new RoomMessageDoc();
        roomMessageDoc.setRoomId(roomId);
        roomMessageDoc.setSendUid("0");
        roomMessageDoc.setMsgType(MessageTypeEnum.SYS.getCode());
        roomMessageDoc.setContextType(ContextTypeEnum.TEXT.getType());
        roomMessageDoc.setMsgStatus(MessageStatusEnum.NORMAL.getStatus());
        Map<String, String> map = Maps.newHashMap();
        map.put(applyUid, String.format("您与%s成为好友,开始聊天吧", friendUid));
        map.put(friendUid, String.format("您与%s成为好友,开始聊天吧", applyUid));
        roomMessageDoc.setContext(JSONObject.toJSONString(map));
        roomMessageDoc.setSendTime(now);
        roomMessageDocService.save(roomMessageDoc);

        long timestampInSeconds = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

        // 创建房间-用户活跃度缓存
        CacheUtils.zAdd(String.format(CommonConstant.ROOM_USER_KEY, roomId) , applyUid, timestampInSeconds);
        CacheUtils.zAdd(String.format(CommonConstant.ROOM_USER_KEY, roomId), friendUid, timestampInSeconds);

        // 创建用户-房间活跃度缓存
        CacheUtils.zAdd(String.format(CommonConstant.USER_ROOM_KEY, applyUid), roomId, timestampInSeconds);
        CacheUtils.zAdd(String.format(CommonConstant.USER_ROOM_KEY, friendUid), roomId, timestampInSeconds);

        // 设置房间最后一条消息
        RLock lock = redissonClient.getLock(String.format(CommonConstant.SEND_ROOM_MESSAGE_LOCK_KEY, roomId));
        try {
            lock.lock();
            redisTemplate.opsForValue().set(String.format(CommonConstant.ROOM_INFO_KEY, roomId), JSON.toJSONString(map));
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return "success";
    }


}
